package com.itzhanshen.auth.config;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.itzhanshen.auth.entity.IntergrationAuthenticationEntity;
import com.itzhanshen.auth.entity.RequestParamsThreadLocal;
import com.itzhanshen.auth.entity.UserHolder;
import com.itzhanshen.auth.processor.AuthenticationProcessor;
import com.itzhanshen.sys.feign.SysUserFeign;
import com.nineclock.common.constant.NcConstant;
import com.nineclock.common.entity.NcAuthority;
import com.nineclock.common.entity.UserInfo;
import com.nineclock.common.enums.ResponseEnum;
import com.nineclock.common.exception.NCException;
import com.nineclock.common.utils.BeanHelper;
import com.nineclock.dto.SysCompanyUserDTO;
import com.nineclock.dto.SysUserDTO;
import io.jsonwebtoken.lang.Collections;
import org.apache.commons.lang3.StringUtils;
import org.mockito.internal.util.StringUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;
import springfox.documentation.spring.web.json.Json;

import java.util.*;

@Component
public class UserDetailsServiceImpl implements UserDetailsService {
    @Autowired
    private List<AuthenticationProcessor> processors;
    @Autowired
    SysUserFeign sysUserFeign;

    //private Collection<AuthenticationProcessor> processors;
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        // 根据ThreadLocal获取参数
        IntergrationAuthenticationEntity entity = RequestParamsThreadLocal.get();
        if (entity == null) {
            throw new NCException(ResponseEnum.ERROR);
        }
        String authType = entity.getAuthType();
        // 根据authType选择认证器
        System.out.println(this.getClass().getSimpleName());
        AuthenticationProcessor processor = this.pickAuthenticationProcessor(entity);
        System.out.println("得到的选择器为:" + processor.getClass().getSimpleName());
        // 用户基本信息
        SysUserDTO sysUserDTO = processor.authenticate(entity);
        // 组装数据并返回
        // 由于传输的数据有敏感信息密码,重新封装
        UserInfo userInfo = BeanHelper.copyProperties(sysUserDTO, UserInfo.class);

        /*-----------认证功能完善----------*/

        // - 判定当前认证是否是PC端认证 client_id
        String clientId = entity.getAuthParameter("client_id");
        String companyId = entity.getAuthParameter("company_id");
        userInfo.setClientId(clientId);

        if ("pc_client".equals(clientId)) {

            //- 根据用户ID查询用户管理企业员工信息
            Long userId = sysUserDTO.getId();
            //Long userId = userInfo.getId();
            List<SysCompanyUserDTO> companyUserDTOList = sysUserFeign.findCompanyUserByUserIdAndCompanyId(userId, null).getData();
            if (companyUserDTOList == null) {
                // 远程调用没查询到数据
                throw new NCException(ResponseEnum.ROLE_NOT_FOUND);
            }
            //- 判定当前员工是否是管理员, 如果是, 则允许继续操作
            companyUserDTOList.forEach(sysCompanyUserDTO -> {
                sysCompanyUserDTO.getRoles().forEach(sysRoleDTO -> {
                    String roleName = sysRoleDTO.getRoleName(); //ROLE_ADMIN_SYS
                    if (!roleName.startsWith(NcConstant.ADMIN_ROLE_PREFIX)) {
                        // 不是企业管理员
                        throw new NCException(ResponseEnum.USER_NOT_COMPANY_ADMIN);
                    }
                });
            });
            //- 判定当前用户管理的企业信息 , 如果只有一个企业,无需认证 组装用户关联的企业信息,
            if (companyUserDTOList.size() == 1) {
                addUserInfo(userInfo, companyUserDTOList.get(0));
            }
            //- 如果前端传递companyId, 则是选择了企业,根据用户ID, 企业ID查询员工信息, 并封装返回 ;
            if (StringUtils.isNotEmpty(companyId)) {
                List<SysCompanyUserDTO> companyUserDTOS = sysUserFeign.findCompanyUserByUserIdAndCompanyId(sysUserDTO.getId(), Long.valueOf(companyId)).getData();
                if (!Collections.isEmpty(companyUserDTOS)) {
                    addUserInfo(userInfo, companyUserDTOS.get(0));
                }
            }
        } else {
            /*---------app端------------*/
            //如果没有传递companyId, 使用默认登录最后登录的companyId
            if (StringUtils.isEmpty(companyId)) {
                companyId = String.valueOf(sysUserDTO.getLastLoginCompanyId());
            }
            // 获取员工信息
            List<SysCompanyUserDTO> companyUserDTOS = sysUserFeign.findCompanyUserByUserIdAndCompanyId(sysUserDTO.getId(), Long.valueOf(companyId)).getData();
            if (!Collections.isEmpty(companyUserDTOS)) {
                addUserInfo(userInfo, companyUserDTOS.get(0));
            }
        }
        UserHolder.set(userInfo); //存储UserInfo到ThreadLocal
        // 封装数据返回
        return new User(JSON.toJSONString(userInfo), sysUserDTO.getPassword(), AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_ADMIN"));

    }

    //    根据auth选择认证器
    private AuthenticationProcessor pickAuthenticationProcessor(IntergrationAuthenticationEntity entity) {
        for (AuthenticationProcessor processor : processors) {
            System.out.println(processor);
            if (processor.support(entity)) {
                System.out.println("----<<<< " + processor + ">>>>>>-----------");
                return processor;
            }
        }
        return null;
    }

    // 在 userInfo中封装用户关联的信息
    public void addUserInfo(UserInfo userInfo, SysCompanyUserDTO sysCompanyUserDTO) {
        userInfo.setCompanyId(sysCompanyUserDTO.getCompanyId());
        userInfo.setCompanyName(sysCompanyUserDTO.getCompanyName());
        userInfo.setCompanyUserId(sysCompanyUserDTO.getId());
        userInfo.setDepartmentId(sysCompanyUserDTO.getDepartmentId());
        userInfo.setDepartmentName(sysCompanyUserDTO.getDepartmentName());
        userInfo.setPost(sysCompanyUserDTO.getPost());
        userInfo.setWorkNumber(sysCompanyUserDTO.getWorkNumber());
        userInfo.setTimeEntry(sysCompanyUserDTO.getTimeEntry());
        userInfo.setEnable(true);

        // 封装权限集合
        List<NcAuthority> grantedAuthorities = sysCompanyUserDTO.getGrantedAuthorities();
        if (grantedAuthorities != null) {

            userInfo.setGrantedAuthorities(grantedAuthorities);
        }
    }

}